package com.hframe.http.client;

import com.hframe.http.servlet.HttpSkipServletRequest;
import com.hframe.other.MsgException;
import org.apache.log4j.Logger;
import org.apache.tomcat.util.http.fileupload.FileItem;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;

/**
 * 一个数据上传类， 可上传文件
 *
 * @author heqian
 */
public class HttpUpload {
    /**
     * Http上传数据结构
     *
     * @author heqian
     */
    protected class ReadBuffer {
        public int dataLength = 0; // 上传数据长度
        public int readLength = 0; // 以上传数据长度总和
        public long fileLength = 0; // 文件大小
        public byte[] buffer = new byte[2048];// 上传的数据
    }

    private static Logger log = Logger.getLogger(HttpUpload.class);
    protected String savePath = null;
    protected HttpServletRequest request = null;

    public HttpUpload() {
    }

    public HttpUpload(String savePath) {
        this.savePath = savePath;
        File file = new File(savePath);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 上传数据
     *
     * @param request
     * @return
     * @throws Exception
     */
    public boolean upload(HttpSkipServletRequest request) throws Exception {
        try {
            this.request = request;
            List<FileItem> list = request.getFileList();
            if (null == list)
                return false;

            for (FileItem item : list) {
                if (!item.isFormField()) {

                    File file = null;
                    FileOutputStream out = null;
                    if (null != savePath) {
                        file = startUploadCall(item);
                        if (null == file)
                            continue;
                        out = new FileOutputStream(file);
                    }

                    InputStream in = item.getInputStream();
                    ReadBuffer read = new ReadBuffer();
                    read.fileLength = item.getSize();
                    boolean isFinish = true;
                    try {
                        while ((read.dataLength = in.read(read.buffer)) > 0) {
                            if (!writeBufferCall(read, file))
                                break;

                            if (null != out)
                                out.write(read.buffer, 0, read.dataLength);
                            read.readLength += read.dataLength;
                        }
                    } catch (Exception e) {
                        isFinish = false;
                        throw e;
                    } finally {
                        if (null != out)
                            try {
                                out.close();
                            } catch (Exception e2) {
                                log.error(e2);
                            }

                        try {
                            in.close();
                        } catch (Exception e2) {
                            log.error(e2);
                        }

                        item.delete();
                        finishUploadCall(file, isFinish);
                    }
                }
            }

            return true;
        } catch (MsgException e) {
            onError(e);
            throw e;
        } catch (Exception e) {
            log.error(e, e);
            onError(e);
            throw e;
        }

    }

    protected void onError(Exception e) {

    }


    /**
     * 完成时的回调，重写后，可在上传完成时进行修改名称、删除、移动、拷贝等操作
     *
     * @param file     文件保存路径
     * @param isFinish 是否上传完整
     */

    protected void finishUploadCall(File file, boolean isFinish) throws Exception {
        if (!isFinish)
            file.delete();
    }

    /**
     * 上传数据时的回调，重写后，可用与对数据加解密，效验等操作
     *
     * @param read 上传数据结构
     * @param file 文件保存路径
     * @return
     */
    protected boolean writeBufferCall(ReadBuffer read, File file) throws Exception {
        return true;
    }


    /**
     * 开始上传文件，可用于设置上传文件名，大小过滤
     *
     * @param item
     * @return
     */
    protected File startUploadCall(FileItem item) throws Exception {
        String fileName = item.getName();
        if (fileName == null || "".equals(fileName.trim())) {
            return null;
        }
        return new File(savePath + "/" + fileName);
    }
}
